home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / opxms114.zip / OPXMS.PAS < prev    next >
Pascal/Delphi Source File  |  1992-08-11  |  32KB  |  842 lines

  1. {$S-,R-,V-,I-,B-,F-,O-,A-}
  2.  
  3. {*********************************************************}
  4. {*                   OPXMS.PAS 1.14                      *}
  5. {*       Copyright (c) TurboPower Software 1987, 1989.   *}
  6. {*                 All rights reserved.                  *}
  7. {*********************************************************}
  8.  
  9. unit OpXms;
  10.   {-XMS memory management routines}
  11.  
  12. interface
  13.  
  14. type
  15.   {pointers in XMS are segm:ofs for < 1 meg, and linear for > 1 meg}
  16.   ExtMemPtr      =
  17.     record
  18.       case Boolean of
  19.         False : (RealPtr : Pointer);
  20.         True  : (ProtectedPtr : LongInt);
  21.     end;
  22.  
  23.   {the record structure used internally by MoveExtMemBlock}
  24.   ExtMemMoveStruct =
  25.     record
  26.       Len        : LongInt;
  27.       SrcHand    : Word;
  28.       SrcOffs    : ExtMemPtr;
  29.       DestHand   : Word;
  30.       DestOffs   : ExtMemPtr;
  31.     end;
  32.  
  33. var
  34.   XmsControl       : Pointer;          {ptr to XMS control procedure}
  35.  
  36. const
  37.   FuncNotImplemented   = $80;          {function is not implemented}
  38.   VDiskDeviceDetected  = $81;          {a VDISK compatible device found}
  39.   A20Error             = $82;          {an A20 error occurred}
  40.   GeneralDriverError   = $8E;          {general driver error}
  41.   UnrecoverableError   = $8F;          {unrecoverable driver error}
  42.   HmaDoesNotExist      = $90;          {high memory area does not exist}
  43.   HmaAlreadyInUse      = $91;          {high memory area already in use}
  44.   HmaSizeTooSmall      = $92;          {size requested less than /HMAMIN}
  45.   HmaNotAllocated      = $93;          {high memory area not allocated}
  46.   A20StillEnabled      = $94;          {A20 line is still enabled}
  47.   AllExtMemAllocated   = $A0;          {all extended memory is allocated}
  48.   OutOfExtMemHandles   = $A1;          {extended memory handles exhausted}
  49.   InvalidHandle        = $A2;          {invalid handle}
  50.   InvalidSourceHandle  = $A3;          {invalid source handle}
  51.   InvalidSourceOffset  = $A4;          {invalid source offset}
  52.   InvalidDestHandle    = $A5;          {invalid destination handle}
  53.   InvalidDestOffset    = $A6;          {invalid destination offset}
  54.   InvalidLength        = $A7;          {invalid length}
  55.   OverlapInMoveReq     = $A8;          {overlap in move request}
  56.   ParityErrorDetected  = $A9;          {parity error detected}
  57.   BlockIsNotLocked     = $AA;          {block is not locked}
  58.   BlockIsLocked        = $AB;          {block is locked}
  59.   LockCountOverflowed  = $AC;          {lock count overflowed}
  60.   LockFailed           = $AD;          {lock failed}
  61.   SmallerUMBAvailable  = $B0;          {a smaller upper memory block is avail}
  62.   NoUMBAvailable       = $B1;          {no upper memory blocks are available}
  63.   InvalidUMBSegment    = $B2;          {invalid upper memory block segment}
  64.  
  65. function XmsInstalled : Boolean;
  66.   {-Returns True if an XMS memory manager is installed}
  67.  
  68. function RequestHMA(Bytes : Word) : Byte;
  69.   {-Request the High Memory Area (HMA). Bytes is amount of memory if TSR or
  70.     device driver, or $FFFF if application program.
  71.  
  72.     Possible return codes:
  73.       $00 successful
  74.       $80 if the function is not implemented
  75.       $81 if a VDISK device is detected
  76.       $90 if the HMA does not exist
  77.       $91 if the HMA is already in use
  78.       $92 if Bytes is less than the /HMAMIN= parameter
  79.   }
  80.  
  81. function ReleaseHMA : Byte;
  82.   {-Release the High Memory Area.
  83.  
  84.     Possible return codes:
  85.       $00 successful
  86.       $80 if the function is not implemented
  87.       $81 if a VDISK device is detected
  88.       $90 if the HMA does not exist
  89.       $93 if the HMA was not allocated
  90.   }
  91.  
  92. function GlobalEnableA20 : Byte;
  93.   {-Attempt to enable the A20 line. Should be used only by programs that
  94.     have control of the HMA.
  95.  
  96.     Possible return codes:
  97.       $00 successful
  98.       $80 if the function is not implemented
  99.       $81 if a VDISK device is detected
  100.       $82 if an A20 error occurs
  101.   }
  102.  
  103. function GlobalDisableA20 : Byte;
  104.   {-Attempt to enable the A20 line. Should be used only by programs that
  105.     have control of the HMA.
  106.  
  107.     Possible return codes:
  108.       $00 successful
  109.       $80 if the function is not implemented
  110.       $81 if a VDISK device is detected
  111.       $82 if an A20 error occurs
  112.       $94 if the A20 line is still enabled
  113.   }
  114.  
  115. function LocalEnableA20 : Byte;
  116.   {-Attempt to enable the A20 line. Should be used only by programs that
  117.     need direct access to extended memory.
  118.  
  119.     Possible return codes:
  120.       $00 successful
  121.       $80 if the function is not implemented
  122.       $81 if a VDISK device is detected
  123.       $82 if an A20 error occurs
  124.   }
  125.  
  126. function LocalDisableA20 : Byte;
  127.   {-Attempt to enable the A20 line. Should be used only by programs that
  128.     need direct access to extended memory.
  129.  
  130.     Possible return codes:
  131.       $00 successful
  132.       $80 if the function is not implemented
  133.       $81 if a VDISK device is detected
  134.       $82 if an A20 error occurs
  135.       $94 if the A20 line is still enabled
  136.   }
  137.  
  138. function QueryA20 : Byte;
  139.   {-Checks to see if the A20 line is physically enabled.
  140.  
  141.     Possible return codes:
  142.       $00 A20 line disabled
  143.       $01 A20 line enabled
  144.       $80 if the function is not implemented
  145.       $81 if a VDISK device is detected
  146.   }
  147.  
  148. function QueryFreeExtMem(var TotalFree, LargestBlock : Word) : Byte;
  149.   {-Return the amount of total free extended memory in TotalFree, and the Size
  150.     of the largest free block of extended memory in LargestBlock. Both values
  151.     are specified in number of kilobytes.
  152.  
  153.     Possible function results:
  154.       $00 successful
  155.       $80 if the function is not implemented
  156.       $81 if a VDISK device is detected
  157.       $A0 if all extended memory is allocated
  158.   }
  159.  
  160. function AllocateExtMem(SizeInK : Word; var XmsHandle : Word) : Byte;
  161.   {-Allocate a block of extended memory SizeInK kilobytes in Size, returning
  162.     the XMS handle in XmsHandle.
  163.  
  164.     Possible function results:
  165.       $00 successful
  166.       $80 if the function is not implemented
  167.       $81 if a VDISK device is detected
  168.       $A0 if all extended memory is allocated
  169.       $A1 if all extended memory handles are in use
  170.   }
  171.  
  172. function FreeExtMem(XmsHandle : Word) : Byte;
  173.   {-Free a previously allocated block of extended memory. XmsHandle is the XMS
  174.     handle returned by the previous call to AllocateExtMem.
  175.  
  176.     Possible function results:
  177.       $00 successful
  178.       $80 if the function is not implemented
  179.       $81 if a VDISK device is detected
  180.       $A2 if XmsHandle is invalid
  181.       $AB if XmsHandle is currently locked
  182.   }
  183. function MoveExtMemBlock(BlockLength : LongInt;
  184.                          SourceHandle : Word;
  185.                          SourcePtr : ExtMemPtr;
  186.                          DestHandle : Word;
  187.                          DestPtr : ExtMemPtr) : Byte;
  188.   {-Move a block of memory. Intended primarily for moving data to and from
  189.     extended memory and conventional memory. Can also move memory from
  190.     extended to extended and conventional to conventional. BlockLength must
  191.     always be an even number. Memory areas may overlap ONLY if SourcePtr is at
  192.     a lower address than DestPtr. If SourceHandle is 0, then SourcePtr is
  193.     interpreted as a normal segment:offset dword pointer. If SourceHandle is
  194.     non-zero, then the SourcePtr is interpreted as a 32 bit linear offset into
  195.     the extended memory associated with SourceHandle. The same is true for
  196.     DestHandle and DestPtr. This routine does NOT require that the A20 be
  197.     enabled. Extended memory blocks used as SourcePtr or DestPtr need not be
  198.     locked before calling this routine (although they may be locked).
  199.  
  200.     Possible function results:
  201.       $00 successful
  202.       $80 if the function is not implemented
  203.       $81 if a VDISK device is detected
  204.       $82 if an A20 error occurs
  205.       $A3 if SourceHandle is invalid
  206.       $A4 if SourcePtr is invalid
  207.       $A5 if DestHandle is invalid
  208.       $A6 if DestPtr is invalid
  209.       $A7 if BlockLen is invalid
  210.       $A8 if SourcePtr and DestPtr contain an invalid overlap
  211.       $A9 if a memory parity error occurs
  212.   }
  213.  
  214. function LockExtMemBlock(XmsHandle : Word;
  215.                          var LockedBlock : ExtMemPtr) : Byte;
  216.   {-Locks an extended memory block and returns its base address as a 32 bit
  217.     linear address. Locked extended memory blocks are guaranteed not to move.
  218.     The LockedBlock address is valid only while the block is locked. Locked
  219.     extended memory blocks should be unlocked as quickly as possible. It is
  220.     not necessary to lock a block before calling MoveExtMemBlock. A count of
  221.     the number of locks is maintained by the XMS memory manager and can be
  222.     retrieved with the GetHandleInfo function.
  223.  
  224.     Possible function results:
  225.       $00 successful
  226.       $80 if the function is not implemented
  227.       $81 if a VDISK device is detected
  228.       $A2 if XmsHandle is invalid
  229.       $AC if the block's lock count overflows
  230.       $AD if the lock fails
  231.   }
  232.  
  233. function UnlockExtMemBlock(XmsHandle : Word) : Byte;
  234.   {-Unlocks an extended memory block. Any 32 bit linear addresses in use
  235.     obtained by calling LockExtMemBlock are invalid after UnlockExtMemBlock is
  236.     called.
  237.  
  238.     Possible function results:
  239.       $00 successful
  240.       $80 if the function is not implemented
  241.       $81 if a VDISK device is detected
  242.       $A2 if XmsHandle is invalid
  243.       $AC if the block's lock count overflows
  244.       $AA if the block is not locked
  245.   }
  246.  
  247. function GetHandleInfo(XmsHandle : Word;
  248.                        var LockCount    : Byte;
  249.                        var HandlesLeft  : Byte;
  250.                        var BlockSizeInK : Word) : Byte;
  251.   {-Return information about an extended memory handle. The lock count for
  252.     this handle, the number of XMS handles left, and the Size in kilobytes of
  253.     this handle are returned. To retrieve the 32 bit linear address of this
  254.     handle, you must call LockExtMemBlock.
  255.  
  256.   Possible function results:
  257.       $00 successful
  258.       $80 if the function is not implemented
  259.       $81 if a VDISK device is detected
  260.       $A2 if XmsHandle is invalid
  261.   }
  262.  
  263. function ResizeExtMemBlock(XmsHandle : Word; NewSizeInK : Word) : Byte;
  264.   {-Attempts to resize the memory block associated with XmsHandle. The
  265.     extended memory block must be unlocked. If the NewSizeInK is bigger than
  266.     the previous Size, then all data is preserved. If it is smaller, then all
  267.     data beyond the end of the new block Size is lost.
  268.  
  269.   Possible function results:
  270.       $00 successful
  271.       $80 if the function is not implemented
  272.       $81 if a VDISK device is detected
  273.       $A0 if all extended memory is allocated
  274.       $A1 if all extended memory handles are in use
  275.       $A2 if XmsHandle is invalid
  276.       $AB if the block is locked
  277.   }
  278.  
  279. function AllocUpperMemBlock(SizeInParas : Word;
  280.                             var SegmentBase : Word;
  281.                             var Size        : Word) : Byte;
  282.   {-Allocates an upper memory block (UMB). If insufficient memory is available
  283.     in upper memory blocks, then the Size of the largest free upper memory
  284.     block is returned in Size. If this functions succeeds, then SegmentBase
  285.     contains the segment of the allocated upper memory block. Upper memory
  286.     blocks are paragraphed aligned (the offset is always 0).
  287.  
  288.     By definition, UMBs are located below the 1 meg address boundary.
  289.     Therefore the A20 line need not be enabled to access the memory in a UMB.
  290.     Therefore there are no restrictions on using this memory in DOS calls or
  291.     pointing ISRs into this memory.
  292.  
  293.     This function is not implemented by most 286 XMS drivers. It is
  294.     implemented by most 386 products like QEMM and 386^MAX.
  295.  
  296.   Possible function results:
  297.       $00 successful
  298.       $80 if the function is not implemented
  299.       $B0 if a smaller UMB is available
  300.       $B1 if no UMBs are available
  301.   }
  302.  
  303. function FreeUpperMemBlock(SegmentBase : Word) : Byte;
  304.   {-Frees a previously allocated upper memory block.
  305.  
  306.   Possible function results:
  307.       $00 successful
  308.       $80 if the function is not implemented
  309.       $82 if SegmentBase does not refer to a valid UMB
  310.   }
  311.  
  312. function XmsErrorString(ErrorCode : Byte) : String;
  313.   {-Return a string indicating reason for error}
  314.  
  315.   {==========================================================================}
  316.  
  317. implementation
  318.  
  319.   function XmsInstalledPrim : Boolean;
  320.     {-Returns True if an XMS memory manager is installed}
  321.   inline(
  322.     $B8/$00/$43/     {   MOV     AX,$4300           ; XMS Installed function}
  323.     $CD/$2F/         {   INT     $2F                ; DOS Multiplex int}
  324.     $3C/$80/         {   CMP     AL,$80             ; is it there?}
  325.     $75/$04/         {   JNE     NoXmsDriver}
  326.     $B0/$01/         {   MOV     AL,1               ; return True}
  327.     $EB/$02/         {   JMP     SHORT XIExit}
  328.                      {NoXmsDriver:}
  329.     $30/$C0);        {   XOR     AL,AL              ; return False}
  330.                      {XIExit:}
  331.  
  332.   function XmsInstalled : Boolean;
  333.     {-Returns True if an XMS memory manager is installed}
  334.   begin
  335.     XmsInstalled := XmsControl <> Nil;
  336.   end;
  337.  
  338.   function RequestHMAPrim(Bytes : Word) : Byte;
  339.   inline(
  340.     $5A/                   {  POP      DX      ; get Bytes}
  341.     $B4/$01/               {  MOV      AH,1    ; XMS function 1 - Request HMA}
  342.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  343.     $09/$C0/               {  OR       AX,AX}
  344.     $74/$04/               {  JZ       Error}
  345.     $30/$C0/               {  XOR      AL,AL}
  346.     $EB/$02/               {  JMP      SHORT ExitPoint}
  347.                            {Error:}
  348.     $88/$D8);              {  MOV      AL,BL}
  349.                            {ExitPoint:}
  350.  
  351.   function RequestHMA(Bytes : Word) : Byte;
  352.     {-Request the High Memory Area (HMA). Bytes is amount of memory if TSR or
  353.       device driver, or $FFFF if application program.
  354.  
  355.       Possible return codes:
  356.         $00 successful
  357.         $80 if the function is not implemented
  358.         $81 if a VDISK device is detected
  359.         $90 if the HMA does not exist
  360.         $91 if the HMA is already in use
  361.         $92 if Bytes is less than the /HMAMIN= parameter
  362.     }
  363.   begin
  364.     RequestHMA := RequestHMAPrim(Bytes)
  365.   end;
  366.  
  367.   function ReleaseHMAPrim : Byte;
  368.   inline(
  369.     $B4/$02/               {  MOV      AH,2    ; XMS function 2 - Release HMA}
  370.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  371.     $09/$C0/               {  OR       AX,AX}
  372.     $74/$04/               {  JZ       Error}
  373.     $30/$C0/               {  XOR      AL,AL}
  374.     $EB/$02/               {  JMP      SHORT ExitPoint}
  375.                            {Error:}
  376.     $88/$D8);              {  MOV      AL,BL}
  377.                            {ExitPoint:}
  378.  
  379.   function ReleaseHMA : Byte;
  380.     {-Release the High Memory Area.
  381.  
  382.       Possible return codes:
  383.         $00 successful
  384.         $80 if the function is not implemented
  385.         $81 if a VDISK device is detected
  386.         $90 if the HMA does not exist
  387.         $93 if the HMA was not allocated
  388.     }
  389.   begin
  390.     ReleaseHMA := ReleaseHMAPrim;
  391.   end;
  392.  
  393.   function GlobalEnableA20Prim : Byte;
  394.   inline(
  395.     $B4/$03/               {  MOV AH,3      ; XMS function 3 - Global Enable A20}
  396.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  397.     $09/$C0/               {  OR       AX,AX}
  398.     $74/$04/               {  JZ       Error}
  399.     $30/$C0/               {  XOR      AL,AL}
  400.     $EB/$02/               {  JMP      SHORT ExitPoint}
  401.                            {Error:}
  402.     $88/$D8);              {  MOV      AL,BL}
  403.                            {ExitPoint:}
  404.  
  405.   function GlobalEnableA20 : Byte;
  406.     {-Attempt to enable the A20 line. Should be used only by programs that
  407.       have control of the HMA.
  408.  
  409.       Possible return codes:
  410.         $00 successful
  411.         $80 if the function is not implemented
  412.         $81 if a VDISK device is detected
  413.         $82 if an A20 error occurs
  414.     }
  415.   begin
  416.     GlobalEnableA20 := GlobalEnableA20Prim;
  417.   end;
  418.  
  419.   function GlobalDisableA20Prim : Byte;
  420.   inline(
  421.     $B4/$04/               {  MOV AH,4      ; XMS function 4 - Global Disable A20}
  422.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  423.     $09/$C0/               {  OR       AX,AX}
  424.     $74/$04/               {  JZ       Error}
  425.     $30/$C0/               {  XOR      AL,AL}
  426.     $EB/$02/               {  JMP      SHORT ExitPoint}
  427.                            {Error:}
  428.     $88/$D8);              {  MOV      AL,BL}
  429.                            {ExitPoint:}
  430.  
  431.   function GlobalDisableA20 : Byte;
  432.     {-Attempt to enable the A20 line. Should be used only by programs that
  433.       have control of the HMA.
  434.  
  435.       Possible return codes:
  436.         $00 successful
  437.         $80 if the function is not implemented
  438.         $81 if a VDISK device is detected
  439.         $82 if an A20 error occurs
  440.         $94 if the A20 line is still enabled
  441.     }
  442.   begin
  443.     GlobalDisableA20 := GlobalDisableA20Prim;
  444.   end;
  445.  
  446.   function LocalEnableA20Prim : Byte;
  447.   inline(
  448.     $B4/$05/               {  MOV AH,5      ; XMS function 3 - Local Enable A20}
  449.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  450.     $09/$C0/               {  OR       AX,AX}
  451.     $74/$04/               {  JZ       Error}
  452.     $30/$C0/               {  XOR      AL,AL}
  453.     $EB/$02/               {  JMP      SHORT ExitPoint}
  454.                            {Error:}
  455.     $88/$D8);              {  MOV      AL,BL}
  456.                            {ExitPoint:}
  457.  
  458.   function LocalEnableA20 : Byte;
  459.     {-Attempt to enable the A20 line. Should be used only by programs that
  460.       need direct access to extended memory.
  461.  
  462.       Possible return codes:
  463.         $00 successful
  464.         $80 if the function is not implemented
  465.         $81 if a VDISK device is detected
  466.         $82 if an A20 error occurs
  467.     }
  468.   begin
  469.     LocalEnableA20 := LocalEnableA20Prim;
  470.   end;
  471.  
  472.   function LocalDisableA20Prim : Byte;
  473.   inline(
  474.     $B4/$06/               { MOV AH,6 ;XMS function 6 - Local Disable A20 !!.03}
  475.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  476.     $09/$C0/               {  OR       AX,AX}
  477.     $74/$04/               {  JZ       Error}
  478.     $30/$C0/               {  XOR      AL,AL}
  479.     $EB/$02/               {  JMP      SHORT ExitPoint}
  480.                            {Error:}
  481.     $88/$D8);              {  MOV      AL,BL}
  482.                            {ExitPoint:}
  483.  
  484.   function LocalDisableA20 : Byte;
  485.     {-Attempt to enable the A20 line. Should be used only by programs that
  486.       need direct access to extended memory.
  487.  
  488.       Possible return codes:
  489.         $00 successful
  490.         $80 if the function is not implemented
  491.         $81 if a VDISK device is detected
  492.         $82 if an A20 error occurs
  493.         $94 if the A20 line is still enabled
  494.     }
  495.   begin
  496.     LocalDisableA20 := LocalDisableA20Prim;
  497.   end;
  498.  
  499.   function QueryA20Prim : Byte;
  500.   inline(
  501.     $B4/$07/               {  MOV      AH,7 ; XMS Function 7 - Query A20 !!.03}
  502.     $FF/$1E/>XmsControl/   {  CALL     DWORD PTR [>XmsControl]}
  503.     $08/$DB/               {  OR       BL,BL}
  504.     $74/$02/               {  JZ       ExitPoint}
  505.     $88/$D8);              {  MOV      AL,BL}
  506.                            {ExitPoint:}
  507.  
  508.   function QueryA20 : Byte;
  509.     {-Checks to see if the A20 line is physically enabled.
  510.  
  511.       Possible return codes:
  512.         $00 A20 line disabled
  513.         $01 A20 line enabled
  514.         $80 if the function is not implemented
  515.         $81 if a VDISK device is detected
  516.     }
  517.   begin
  518.     QueryA20 := QueryA20Prim;
  519.   end;
  520.  
  521.   function QueryFreeExtMem(var TotalFree, LargestBlock : Word) : Byte;
  522.   var
  523.     ErrorCode : Byte;
  524.   begin
  525.     inline(
  526.       $B4/$08/               {  MOV    AH,$08   ;XMS function 08h - Query Free ext memory}
  527.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  528.       $09/$C0/               {  OR     AX,AX}
  529.       $74/$10/               {  JZ     SetError}
  530.       $30/$DB/               {  XOR    BL,BL}
  531.       $C4/$BE/>TotalFree/    {  LES    DI,>TotalFree[BP]}
  532.       $26/                   {ES:}
  533.       $89/$15/               {  MOV    [DI],DX}
  534.       $C4/$BE/>LargestBlock/ {  LES    DI,>LargestBlock[BP]}
  535.       $26/                   {ES:}
  536.       $89/$05/               {  MOV    [DI],AX}
  537.                              {SetError:}
  538.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  539.     QueryFreeExtMem := ErrorCode;
  540.   end;
  541.  
  542.   function AllocateExtMem(SizeInK : Word; var XmsHandle : Word) : Byte;
  543.   var
  544.     ErrorCode : Byte;
  545.   begin
  546.     inline(
  547.       $B4/$09/               {  MOV    AH,$09   ;XMS function 09h - Alloc ext memory block}
  548.       $8B/$96/>SizeInK/      {  MOV    DX,>SizeInK[BP]}
  549.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  550.       $A9/$01/$00/           {  TEST   AX,1}
  551.       $74/$09/               {  JZ     SetError}
  552.       $30/$DB/               {  XOR    BL,BL}
  553.       $C4/$BE/>XmsHandle/    {  LES    DI,>XmsHandle[BP]}
  554.       $26/                   {ES:}
  555.       $89/$15/               {  MOV    [DI],DX  ;return XMS handle}
  556.                              {SetError:}
  557.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  558.     AllocateExtMem := ErrorCode;
  559.   end;
  560.  
  561.   function FreeExtMem(XmsHandle : Word) : Byte;
  562.   var
  563.     ErrorCode : Byte;
  564.   begin
  565.     inline(
  566.       $B4/$0A/               {  MOV    AH,$0A   ;XMS function 0Ah - Free ext memory block}
  567.       $8B/$96/>XmsHandle/    {  MOV    DX,>XmsHandle[BP]}
  568.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  569.       $A9/$01/$00/           {  TEST   AX,1}
  570.       $74/$02/               {  JZ     SetError}
  571.       $30/$DB/               {  XOR    BL,BL}
  572.                              {SetError:}
  573.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  574.     FreeExtMem := ErrorCode;
  575.   end;
  576.  
  577.   function MoveExtMemBlockPrim(ParamBlock : Pointer) : Byte;
  578.     {-Call XMS function $0B to move extended memory}
  579.   inline(
  580.     $8C/$D8/               {  MOV    AX,DS}
  581.     $8E/$C0/               {  MOV    ES,AX}
  582.     $5E/                   {  POP    SI}
  583.     $1F/                   {  POP    DS}
  584.     $50/                   {  PUSH   AX}
  585.     $B4/$0B/               {  MOV    AH,$0B   ;XMS function 0Bh - Move Extended}
  586.     $26/                   {ES:}
  587.     $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  588.     $1F/                   {  POP    DS}
  589.     $A9/$01/$00/           {  TEST   AX,1}
  590.     $75/$04/               {  JNZ    Success}
  591.     $88/$D8/               {  MOV    AL,BL}
  592.     $EB/$02/               {  JMP    SHORT ExitPoint}
  593.                            {Success:}
  594.     $30/$C0);              {  XOR    AL,AL}
  595.                            {ExitPoint:}
  596.  
  597.  
  598.   function MoveExtMemBlock(BlockLength : LongInt;
  599.                            SourceHandle : Word;
  600.                            SourcePtr : ExtMemPtr;
  601.                            DestHandle : Word;
  602.                            DestPtr : ExtMemPtr) : Byte;
  603.   var
  604.     ControlBlock : ExtMemMoveStruct;
  605.   begin
  606.     with ControlBlock do begin
  607.       Len := BlockLength;
  608.       SrcHand   := SourceHandle;
  609.       SrcOffs   := SourcePtr;
  610.       DestHand  := DestHandle;
  611.       DestOffs  := DestPtr;
  612.       MoveExtMemBlock := MoveExtMemBlockPrim(@ControlBlock);
  613.     end;
  614.   end;
  615.  
  616.   function LockExtMemBlock(XmsHandle : Word;
  617.                            var LockedBlock : ExtMemPtr) : Byte;
  618.   var
  619.     ErrorCode : Byte;
  620.   begin
  621.     inline(
  622.       $B4/$0C/               {  MOV    AH,$0C   ;XMS function 0Ch - Lock ext memory block}
  623.       $8B/$96/>XmsHandle/    {  MOV    DX,>XmsHandle[BP]}
  624.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  625.       $A9/$01/$00/           {  TEST   AX,1}
  626.       $74/$0D/               {  JZ     SetError}
  627.       $C4/$BE/>LockedBlock/  {  LES    DI,>LockedBlock[BP]}
  628.       $26/                   {ES:}
  629.       $89/$1D/               {  MOV    [DI],BX}
  630.       $26/                   {ES:}
  631.       $89/$55/$02/           {  MOV    [DI+2],DX}
  632.       $30/$DB/               {  XOR    BL,BL}
  633.                              {SetError:}
  634.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  635.     LockExtMemBlock := ErrorCode;
  636.   end;
  637.  
  638.   function UnlockExtMemBlock(XmsHandle : Word) : Byte;
  639.   var
  640.     ErrorCode : Byte;
  641.   begin
  642.     inline(
  643.       $B4/$0D/               {  MOV    AH,$0D   ;XMS function 0Dh - Unlock ext memory block}
  644.       $8B/$96/>XmsHandle/    {  MOV    DX,>XmsHandle[BP]}
  645.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  646.       $A9/$01/$00/           {  TEST   AX,1}
  647.       $74/$02/               {  JZ     SetError}
  648.       $30/$DB/               {  XOR    BL,BL}
  649.                              {SetError:}
  650.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  651.     UnlockExtMemBlock := ErrorCode;
  652.   end;
  653.  
  654.   function GetHandleInfo(XmsHandle : Word;
  655.                          var LockCount    : Byte;
  656.                          var HandlesLeft  : Byte;
  657.                          var BlockSizeInK : Word) : Byte;
  658.   var
  659.     ErrorCode : Byte;
  660.   begin
  661.     inline(
  662.       $B4/$0E/               {  MOV    AH,$0E   ;XMS function 0Eh - Get EMB Handle Info}
  663.       $8B/$96/>XmsHandle/    {  MOV    DX,>XmsHandle[BP]}
  664.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  665.       $A9/$01/$00/           {  TEST   AX,1}
  666.       $74/$17/               {  JZ     SetError}
  667.       $C4/$BE/>LockCount/    {  LES    DI,>LockCount[BP]}
  668.       $26/                   {ES:}
  669.       $88/$3D/               {  MOV    BYTE PTR [DI],BH}
  670.       $C4/$BE/>HandlesLeft/  {  LES    DI,>HandlesLeft[BP]}
  671.       $26/                   {ES:}
  672.       $88/$1D/               {  MOV    BYTE PTR [DI],BL}
  673.       $C4/$BE/>BlockSizeInK/ {  LES    DI,>BlockSizeInK[BP]}
  674.       $26/                   {ES:}
  675.       $89/$15/               {  MOV    [DI],DX}
  676.       $30/$DB/               {  XOR    BL,BL}
  677.                              {SetError:}
  678.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  679.     GetHandleInfo := ErrorCode;
  680.   end;
  681.  
  682.   function ResizeExtMemBlock(XmsHandle : Word; NewSizeInK : Word) : Byte;
  683.   var
  684.     ErrorCode : Byte;
  685.   begin
  686.     inline(
  687.       $B4/$0F/               {  MOV    AH,$0F   ;XMS function 0Fh - Resize Ext mem block}
  688.       $8B/$96/>XmsHandle/    {  MOV    DX,>XmsHandle[BP]}
  689.       $8B/$9E/>NewSizeInK/   {  MOV    BX,>NewSizeInK[BP]}
  690.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  691.       $A9/$01/$00/           {  TEST   AX,1}
  692.       $74/$02/               {  JZ     SetError}
  693.       $30/$DB/               {  XOR    BL,BL}
  694.                              {SetError:}
  695.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  696.     ResizeExtMemBlock := ErrorCode;
  697.   end;
  698.  
  699.   function AllocUpperMemBlock(SizeInParas : Word;
  700.                               var SegmentBase : Word;
  701.                               var Size        : Word) : Byte;
  702.   var
  703.     ErrorCode : Byte;
  704.   begin
  705.     inline(
  706.       $B4/$10/               {  MOV    AH,$10   ;XMS function 10h - Alloc UMB}
  707.       $8B/$96/>SizeInParas/  {  MOV    DX,>SizeInParas[BP]}
  708.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  709.       $A9/$01/$00/           {  TEST   AX,1}
  710.       $74/$12/               {  JZ     Error}
  711.       $C4/$BE/>Size/         {  LES    DI,>Size[BP]}
  712.       $26/                   {ES:}
  713.       $89/$15/               {  MOV    [DI],DX        ;return actual Size}
  714.       $C4/$BE/>SegmentBase/  {  LES    DI,>SegmentBase[BP]}
  715.       $26/                   {ES:}
  716.       $89/$1D/               {  MOV    [DI],BX        ;return segment base}
  717.       $30/$DB/               {  XOR    BL,BL}
  718.       $EB/$07/               {  JMP    SHORT SetError}
  719.                              {Error:}
  720.       $C4/$BE/>Size/         {  LES    DI,>Size[BP]}
  721.       $26/                   {ES:}
  722.       $89/$15/               {  MOV    [DI],DX        ;return largest avail block}
  723.                              {SetError:}
  724.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  725.     AllocUpperMemBlock := ErrorCode;
  726.   end;
  727.  
  728.   function FreeUpperMemBlock(SegmentBase : Word) : Byte;
  729.   var
  730.     ErrorCode : Byte;
  731.   begin
  732.     inline(
  733.       $B4/$11/               {  MOV    AH,$11   ;XMS function 11h - Free UMB}
  734.       $8B/$96/>SegmentBase/  {  MOV    DX,>SegmentBase[BP]}
  735.       $FF/$1E/>XmsControl/   {  CALL   DWORD PTR [>XmsControl]}
  736.       $A9/$01/$00/           {  TEST   AX,1}
  737.       $74/$02/               {  JZ     SetError}
  738.       $30/$DB/               {  XOR    BL,BL}
  739.                              {SetError:}
  740.       $88/$5E/<ErrorCode);   {  MOV    <ErrorCode[BP],BL}
  741.     FreeUpperMemBlock := ErrorCode;
  742.   end;
  743.  
  744.   function HexB(B : Byte) : string;
  745.     {-Return hex string for byte}
  746.   const
  747.     Digits : array[0..$F] of Char = '0123456789ABCDEF';
  748.   begin
  749.     HexB[0] := #2;
  750.     HexB[1] := Digits[B shr 4];
  751.     HexB[2] := Digits[B and $F];
  752.   end;
  753.  
  754.   function XmsErrorString(ErrorCode : Byte) : String;
  755.     {-Return a string indicating reason for error}
  756.   begin
  757.     case ErrorCode of
  758.       $00 :
  759.         XmsErrorString := 'no XMS error';
  760.       FuncNotImplemented :
  761.         XmsErrorString := 'function not implemented';
  762.       VDiskDeviceDetected :
  763.         XmsErrorString := 'VDISK compatible device detected';
  764.       A20Error :
  765.         XmsErrorString := 'an A20 error occurred';
  766.       GeneralDriverError :
  767.         XmsErrorString := 'general driver error';
  768.       UnrecoverableError :
  769.         XmsErrorString := 'unrecoverable driver error';
  770.       HmaDoesNotExist :
  771.         XmsErrorString := 'high memory area does not exist';
  772.       HmaAlreadyInUse :
  773.         XmsErrorString := 'high memory area already in use';
  774.       HmaSizeTooSmall :
  775.         XmsErrorString := 'size requested less than /HMAMIN= parameter';
  776.       HmaNotAllocated :
  777.         XmsErrorString := 'high memory area not allocated';
  778.       A20StillEnabled :
  779.         XmsErrorString := 'A20 line is still enabled';
  780.       AllExtMemAllocated :
  781.         XmsErrorString := 'all extended memory is allocated';
  782.       OutOfExtMemHandles :
  783.         XmsErrorString := 'extended memory handles exhausted';
  784.       InvalidHandle :
  785.         XmsErrorString := 'invalid handle';
  786.       InvalidSourceHandle :
  787.         XmsErrorString := 'invalid source handle';
  788.       InvalidSourceOffset :
  789.         XmsErrorString := 'invalid source offset';
  790.       InvalidDestHandle :
  791.         XmsErrorString := 'invalid destination handle';
  792.       InvalidDestOffset :
  793.         XmsErrorString := 'invalid destination offset';
  794.       InvalidLength :
  795.         XmsErrorString := 'invalid length';
  796.       OverlapInMoveReq :
  797.         XmsErrorString := 'overlap in move request';
  798.       ParityErrorDetected :
  799.         XmsErrorString := 'parity error detected';
  800.       BlockIsNotLocked :
  801.         XmsErrorString := 'block is not locked';
  802.       BlockIsLocked :
  803.         XmsErrorString := 'block is locked';
  804.       LockCountOverflowed :
  805.         XmsErrorString := 'lock count overflowed';
  806.       LockFailed :
  807.         XmsErrorString := 'lock failed';
  808.       SmallerUMBAvailable :
  809.         XmsErrorString := 'a smaller upper memory block is available';
  810.       NoUMBAvailable :
  811.         XmsErrorString := 'no upper memory blocks are available';
  812.       InvalidUMBSegment :
  813.         XmsErrorString := 'invalid upper memory block segment';
  814.       else
  815.         XmsErrorString := 'unknown XMS error = $' + HexB(ErrorCode);
  816.     end;
  817.   end;
  818.  
  819.   function XmsControlAddr : Pointer;
  820.     {-Return address of XMS control function}
  821.   inline(
  822.     $B8/$10/$43/     {MOV     AX,$4310           ; XMS control func addr}
  823.     $CD/$2F/         {INT     $2F}
  824.     $89/$D8/         {MOV     AX,BX              ; ptr in ES:BX to DX:AX}
  825.     $8C/$C2);        {MOV     DX,ES}
  826.  
  827.   function DosVersion : Word;                    {added !!.12}
  828.     inline(
  829.       $B4/$30/                 {mov ah,$30}
  830.       $CD/$21);                {int $21}
  831.  
  832. begin
  833.   if Lo(DosVersion) >= 3 then begin               {!!.12}
  834.     if XmsInstalledPrim then
  835.       XmsControl := XmsControlAddr
  836.     else
  837.       XmsControl := Nil;
  838.   end
  839.   else                                            {!!.12}
  840.     XmsControl := Nil;                            {!!.12}
  841. end.
  842.